package com.tim.ying.zk.lock;

import java.util.Collections;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import com.tim.ying.zk.util.ZKUtils;

import zk_project.TestDistributeLock;

/**
 * 生成基于zk的分布式锁
 * @author yingbibo
 *
 */
public class DistributeLock implements Watcher{
	
	
	private ZooKeeper zk;
	public final String GROUP_PATH = "/dislock";
	public final String CHILD_PATH = "/locks";
	
	public String waitPath;
	public String selfPath;
	
	
	public DistributeLock(ZooKeeper zk) {
		super();
		this.zk = zk;
	}

	public boolean getLock() throws KeeperException, InterruptedException{
		selfPath = ZKUtils.createNode(zk, GROUP_PATH+CHILD_PATH, null, ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
		System.out.println(Thread.currentThread().getName()+"-创建了锁路径"+selfPath);
		if(checkIsFirst()){
			return true;
		}
		
		return false;
	}
	
	public boolean unLock() throws InterruptedException, KeeperException{
		zk.delete(selfPath, -1);
		System.out.println(Thread.currentThread().getName()+"-完成相关任务...释放锁");
		return false;
	}
	
	public void doWorker() throws InterruptedException, KeeperException{
		System.out.println(Thread.currentThread().getName()+"-开始工作了...");
		Thread.sleep(2000L);
		unLock();
		TestDistributeLock.countDownLatch.countDown();
	}
	
	/**
	 * 判断是不是当前第一个
	 * @return
	 * @throws InterruptedException 
	 * @throws KeeperException 
	 */
	public boolean checkIsFirst() throws KeeperException, InterruptedException{
		List<String> nodeList = zk.getChildren(GROUP_PATH, false);
		Collections.sort(nodeList);
		Integer index = nodeList.indexOf(selfPath.substring(GROUP_PATH.length()+1));
		switch (index) {
		case -1:{
				System.out.println(Thread.currentThread().getName()+"-该节点不存在.... "+selfPath);
				return false;
			}
		case 0:{
				System.out.println(Thread.currentThread().getName()+"-得到锁的第一顺位.... "+selfPath);
				return true;
			}
		default:{
			this.waitPath=GROUP_PATH+"/"+nodeList.get(index-1);
			System.out.println(Thread.currentThread().getName()+"-等待前面一个节点完成任务"+waitPath);
			try {
				zk.getData(waitPath, this, new Stat()); //为了获取前一个节点的数据 如果报错 这可以判断前一个节点已经释放锁了
				return false;
			} catch (Exception e) {
				System.out.println(Thread.currentThread().getName()+"-等待前面一个节点的任务已经完成,本节点得到锁");
				return checkIsFirst();
			}
			}
		}
		
	}
	
	@Override
	public void process(WatchedEvent event) {
		if(event.getType()==Event.EventType.NodeDeleted&&event.getPath().equals(waitPath)){
			System.out.println("前面的已经释放锁了,该节点开始工作");
			try {
				if(checkIsFirst()){
					doWorker();
				}
			} catch (KeeperException | InterruptedException e) {
				e.printStackTrace();
			}
		}	
	}
	
}
